import _ from 'lodash'
import { article, section } from './lablog.js'
import { map } from './util.js'

const log = console.log

const IO = function(f) {
    this.unsafePerform = f
}
IO.of = function(x) {
    return new IO(function() {
        return x
    })
}
IO.prototype.map = function(f) {
    return new IO(_.flowRight(f, this.unsafePerform))
}

const basic = section("IO Basic test")
basic(() => {
    const v = IO.of("ok")
    log("basic IO.of(v).unsafePerform() =", v.unsafePerform())
})

const global = {message: {
    info: 'hello'
}}
const getMessage = (key) => {
    return new IO(function() {
        console.log("GET MESSAGE CALLED")
        return global[key]
    })
}
const extractInfo = (message) => {
    return new IO(function() {
        console.log("GET EXTRACT CALLED")
        return message.info
    })
}



const nested = section("IO nested:")
nested(() => {
    const queryFromObj = _.flowRight(map(extractInfo), getMessage)
    const queryResult = queryFromObj('message')
    log("queryResult:", queryResult)
    // log("queryResult.unsafePerform():", queryResult.unsafePerform())
    log(queryResult.unsafePerform().unsafePerform())
})
/**
 * _.flow(map(extraInfo), getMessage)('message')
 * = map(extraInfo)(getMesssage('message'))
 * = map(extraInfo)(IO(() => global.message))
 * queryResult = new IO(_.flow(extraInfo, () => global.message))
 *
 * queryResult.unsafePerform() = extraInfo(global.message)
 *  = IO(() => globale.message.info)
 * 
 * queryResult.unsafePerform().unsafePerform() = global.message.info
 */
article("如果容器包裹的是函数，这两个相同的容器进行连锁作用之后，（通过 map）进行作用，最终还是会嵌套两层。但是不太一样的是，最外层是拼接完成的一个 flow 函数，执行后再生成下一个 IO，再执行再生成")

const joinSection = section("IO join test:")
// 这样做应该是为了延迟函数执行
IO.prototype.join = function() {
    return new IO(() => this.unsafePerform().unsafePerform())
}
const join = _.curry((functor) => {
    return functor.join()
})
joinSection(() => {
    const queryFromObj = _.flowRight(join, map(extractInfo), getMessage)
    const queryResult = queryFromObj("message")
    log("queryResuslt", queryResult)
    log("queryResult.unsafe()", queryResult.unsafePerform())
})